package com.glut.forum.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.glut.forum.bean.dto.UserDTO;
import com.glut.forum.bean.entity.TbAttention;
import com.glut.forum.bean.entity.User;
import com.glut.forum.bean.vo.UserVO;
import com.glut.forum.common.beans.UserInfo;
import com.glut.forum.common.exceptions.UnloginException;
import com.glut.forum.common.utils.CheckUtil;
import com.glut.forum.common.utils.JWTUtils;
import com.glut.forum.common.utils.StringUtil;
import com.glut.forum.common.utils.UserUtil;
import com.glut.forum.mapper.UserMapper;
import com.glut.forum.service.ITbAttentionService;
import com.glut.forum.service.IUserService;
import com.glut.forum.service.QnUploadService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.sql.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author jobob
 * @since 2021-09-02
 */
@Service
@Slf4j
@Data
@AllArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final MapperFacade mapperFacade;

    private final ITbAttentionService ITbAttentionService;

    private final QnUploadService qnUploadService;


    // (注：\为转义字符）
    final String regexp = "[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\\.[a-zA-Z0-9]+)+";

    /**
     * 保存用户接口
     *
     * @param entity
     * @return UserVO
     */
    @Override
    public UserVO saveUser(User entity) {

        log.info("保存用户接受到前端创建用户信息: {}", entity);

        CheckUtil.notNull(entity, "后代接收创建用户信息为空");

        UserVO userVO = null;

        entity.setItemCode(UserUtil.getUUID());

        entity.setPassword(UserUtil.encryptPwd(entity.getPassword()));

        super.save(entity);

        // 保存成功
        userVO = mapperFacade.map(entity, UserVO.class);

        return userVO;
    }

    /**
     * 用户登录接口
     * <p>
     * 登录，如果登录成功返回三个参数 token token名字 过期时间 和 用户基本信息
     * <p>
     * Map.put("access_token", token);
     * Map.put("token_type", "token");
     * Map.put("expires_in", "14");
     * Map.put("user", mapperFacade.map(u, UserVO.class));
     * <p>
     * token里面载荷存放了userid
     * <p>
     * 因为map里面参数较少，就不创建VO对象，直接使用Map回传
     */
    public Map<String, Object> login(String account, String password) {

        User u = null;

        QueryWrapper<User> qw = new QueryWrapper<>();

        // 先判断用户和密码是否为空
        CheckUtil.notEmpty(account, "account.is.null");

        CheckUtil.notEmpty(password, "password.is.null");

        if (account.matches(regexp)) {

            qw.eq("email", account);

            qw.and(wrapper -> wrapper.eq("password", UserUtil.encryptPwd(password)));

        } else {

            qw.eq("item_id", Integer.valueOf(account));

            qw.and(wrapper -> wrapper.eq("password", UserUtil.encryptPwd(password)));

        }

        System.out.println(StringUtil.isEmpty((CharSequence) account));

        log.info("登录查询, account: {} --- password {}", account, password);

        u = super.getOne(qw);

        // 如果不为空就是登录成功
        CheckUtil.notNull(u, "用户登录信息不正确");

        Map<String, String> tokenInfo = new HashMap<>();

        tokenInfo.put("userId", u.getItemId().toString());

        tokenInfo.put("userCode", u.getItemCode());

        // 生成token
        String token = JWTUtils.getToken(tokenInfo, 14);

        log.info("生成token---{}", token);

        Map<String, Object> resMap = new HashMap<>();

        resMap.put("access_token", token);

        resMap.put("token_type", "token");

        resMap.put("expires_in", "14");

        resMap.put("user", mapperFacade.map(u, UserVO.class));

        return resMap;
    }

    /**
     * 根据用户id和用户item_code获取用户详细信息
     */
    @Override
    public UserDTO getUserFormatToUserDTO(UserInfo userInfo) {
        // 先判断用户id
        CheckUtil.notNull(userInfo.getItemId(), "id.is.null");

        log.info("getUserFormatToUserDTO---id-{}", userInfo.getItemId());

        UserDTO ud = mapperFacade.map(this.getById(userInfo.getItemId()), UserDTO.class);

        // 统计用户的粉丝数量
        QueryWrapper<TbAttention> qw = new QueryWrapper<>();

        qw.eq("by_attention_user_code", userInfo.getItemCode());

        ud.setFollowerCount(ITbAttentionService.count(qw));

        qw.clear();

        // 统计用户的关注数量
        qw.eq("attention_user_code", userInfo.getItemCode());

        ud.setAttention_count(ITbAttentionService.count(qw));

        return ud;
    }

    /**
     * 根据用户id获取用户详细信息
     *
     * @param id
     * @return
     */
    @Override
    public UserDTO getUserFormatToUserDTO(Integer id) {
        // 先判断用户id
        CheckUtil.notNull(id, "id.is.null");

        String itemCode = super.getById(id).getItemCode();

        UserInfo userInfo = new UserInfo(id, itemCode);

        return this.getUserFormatToUserDTO(userInfo);
    }

    /**
     * 修改当前登录用户信息
     *
     * @param uv
     * @return
     */
    @Override
    public UserVO updateUserInfo(UserVO uv) {

        log.info("更改id: {}用户信息 --- {}", uv.getItemId(), uv);
        // 属性映射
        User user = mapperFacade.map(uv, User.class);
        log.info("更改: {}", user);

        // 获取当前时间戳
        user.setUpdateTime(new Date(System.currentTimeMillis()));
        // 如果没异常代表更新成功
        super.lambdaUpdate()
                .eq(User::getItemId, user.getItemId())
                .set(User::getDescription, user.getDescription())
                .set(User::getEmail, user.getEmail())
                .set(User::getNickName, user.getNickName())
                .set(User::getPhone, user.getPhone())
                .set(User::getAvatarsUrl, user.getAvatarsUrl())
                .update();

        return uv;
    }

    @Override
    public UserVO updateLoginUserInfo(UserVO uv, UserInfo userInfo) {

        log.info("更新用户id: {} 用户信息", uv.getItemId());

        log.info("当前id: {} 用户信息", userInfo.getItemId());

        // 判断传入的用户id是否为当前登录id
        if (StringUtil.equal(uv.getItemId().toString(), userInfo.getItemId().toString())) {

            return updateUserInfo(uv);

        } else {

            CheckUtil.infoError("用户信息与当前登录信息不符合, 请仔细检查");

        }

        return null;
    }

    /**
     * 根据用户id获取用户信息(非详细)
     *
     * @param id
     * @return
     */
    @Override
    public UserVO getUserInfoById(Integer id) {

        log.info("获取id: {} 用户信息(非详细)", id);

        CheckUtil.notNull(id, "id.is.null");

        return mapperFacade.map(super.getById(id), UserVO.class);
    }

    /**
     * 判断邮箱或者电话号码是否存在
     *
     * @param value
     * @param column
     * @return
     */
    @Override
    public Boolean checkStatus(String value, String column) {

        log.info("查询列{}, 值为{}", column, value);

        CheckUtil.notEmpty(value, column + ".is.null");

        QueryWrapper<User> qw = new QueryWrapper<>();

        qw.eq(column, value);

        return super.count(qw) >= 1;
    }

    /**
     * 修改密码, 已登录的时候
     *
     * @param password
     * @param userInfo
     * @return
     */
    @Override
    public Boolean updatePwd(String password, UserInfo userInfo) {

        log.info("修改密码用户id: {}", userInfo.getItemId());

        log.info("修改密码用户密码: {}", UserUtil.encryptPwd(password));

        CheckUtil.notEmpty(userInfo.getItemCode(), "token.info.error");

        super.lambdaUpdate()
                .eq(User::getItemId, userInfo.getItemId())
                .set(User::getPassword, UserUtil.encryptPwd(password))
                .update();

        return true;
    }

    /**
     * 验证当前登录用户传入的密码是否正确
     *
     * @param password
     * @param userInfo
     * @return
     */
    @Override
    public Boolean authPwd(String password, UserInfo userInfo) {

        log.info("验证当前登录用户id: {}", userInfo.getItemId());

        log.info("验证当前登录用户密码: {}", UserUtil.encryptPwd(password));

        Map<String, Object> resultMap = super.getMap(new QueryWrapper<User>().eq("item_id", userInfo.getItemId()));

        System.out.println(resultMap);

        return resultMap.get("password").equals(UserUtil.encryptPwd(password));
    }

    /**
     * 修改密码, 未登录的时候
     *
     * @param password
     * @param email
     * @return
     */
    @Override
    public Boolean updatePwdByEmail(String password, String email, String vc) {

        log.info("修改密码传入邮箱: {}", email);

        log.info("修改密码用户密码: {}", UserUtil.encryptPwd(password));

        // 这里应该验证 验证码是否正确

        super.lambdaUpdate()
                .eq(User::getEmail, email)
                .set(User::getPassword, UserUtil.encryptPwd(password))
                .update();

        return true;
    }

    /**
     * 忘记密码
     *
     * @param email
     * @return
     */
    @Override
    public Boolean emailCheck(String email) {

        log.info("忘记密码传入邮箱: {}", email);

        if (this.checkStatus(email, "email")) {
            return true;
        }
        CheckUtil.check(false, "使用该邮箱注册的用户不存在");

        return false;
    }

    /**
     * 接收上传文件，并转发到七牛云服务器，然后写入数据库
     *
     * @param file
     * @param userInfo
     * @return
     */
    @Override
    public Boolean uploadAvatar(MultipartFile file, UserInfo userInfo) {

        log.info("收到上传文件: {}", file.getOriginalFilename());

        // 文件名字
        String fileName = System.currentTimeMillis() + file.getOriginalFilename();

        try {
            // 头像地址
            String avaUrl = qnUploadService.uploadFile(file.getInputStream(), fileName);

            log.info("修改用户{}的头像地址为: {}", userInfo.getItemId(), avaUrl);

            // 修该用户头像地址
            super.lambdaUpdate()
                    .eq(User::getItemId, userInfo.getItemId())
                    .set(User::getAvatarsUrl, avaUrl);

        } catch (IOException e) {

            e.printStackTrace();

            return false;
        }

        return true;
    }
}
